package com.ynet.middleground.mobile.approve.controller;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiUserGetRequest;
import com.dingtalk.api.request.OapiUserGetuserinfoRequest;
import com.dingtalk.api.response.OapiUserGetResponse;
import com.dingtalk.api.response.OapiUserGetuserinfoResponse;
import com.google.common.base.Throwables;
import com.taobao.api.ApiException;
import com.ynet.core.common.ServiceResult;
import com.ynet.core.exception.BusinessException;
import com.ynet.core.log.IfpLogger;
import com.ynet.middleground.mobile.approve.commom.ResponseResult;
import com.ynet.middleground.mobile.approve.conf.AppConfig;
import com.ynet.middleground.mobile.approve.constant.UrlConstant;
import com.ynet.middleground.mobile.approve.exception.DingtalkEncryptException;
import com.ynet.middleground.mobile.approve.request.GetDingtalkAuthCodeReq;
import com.ynet.middleground.mobile.approve.response.ConfigDTO;
import com.ynet.middleground.mobile.approve.response.UserDTO;
import com.ynet.middleground.mobile.approve.service.AuthService;
import com.ynet.middleground.mobile.approve.utils.ApiHelper;
import com.ynet.middleground.mobile.approve.utils.JsApiSignature;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import springfox.documentation.annotations.ApiIgnore;

/**
 * 免登功能
 *
 * @author liulx
 * @date 2020/2/4
 */
@RestController
// NOTE：此处仅为本地调试使用，为避免安全风险，生产环境请勿设置CORS为 '*'
@CrossOrigin("*")
@Api(value = "授权登录相关服务", tags = "授权登录相关服务")
public class AuthController {

    @Autowired
    ApiHelper apiHelper;

    @Autowired
    AppConfig appConfig;

    @Autowired
    AuthService authService;

    /**
     * 欢迎页面，通过 /welcome 访问，判断后端服务是否启动
     *
     * @return 字符串 welcome
     */
    @GetMapping("/welcome")
    @ApiIgnore
    public String welcome() {
        return "welcome";
    }

    /**
     * 钉钉用户登录，显示当前登录用户的信息 <br>
     * 免登录钉钉文档参考
     * {@link https://developers.dingtalk.com/document/app/enterprise-internal-application-logon-free?spm=ding_open_doc.document.0.0.5ebc3492PSZNkm#topic-2021731}
     * 
     * @param req 免登临时 authCode
     * @return 当前用户
     */
    @PostMapping("/login")
    @ApiOperation(value = "钉钉用户登录查询", notes = "钉钉用户登录查询")
    public ResponseResult<UserDTO> login(@RequestBody @Valid GetDingtalkAuthCodeReq req) {
        String accessToken = apiHelper.getAccessToken();

        // 获取用户userId
        ResponseResult<String> userIdSr = getUserInfo(accessToken, req.getAuthCode());
        // 获取用户详情
        ResponseResult<UserDTO> result = new ResponseResult<>();
        try {
            UserDTO user = authService.getUser(userIdSr.getData());
            authService.bindDingtalkUser(user);
            result.setData(user);
        } catch (BusinessException be) {
            result.setError(be.getCode(), be.getMessage());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "用户登录钉钉服务异常, case: {}",
                Throwables.getStackTraceAsString(e));
        }
        return result;
    }

    /**
     * 访问 /user/getuserinfo 接口获取用户 userId
     *
     * @param accessToken access_token
     * @param authCode 临时授权码
     * @return 用户userId或错误信息
     */
    public ResponseResult<String> getUserInfo(String accessToken, String authCode) {
        ResponseResult<String> serviceResult = new ResponseResult<>();
        DingTalkClient client = new DefaultDingTalkClient(UrlConstant.URL_GET_USER_INFO);
        OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
        request.setCode(authCode);
        request.setHttpMethod("GET");

        OapiUserGetuserinfoResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "getUserInfo failed, case: {}",
                Throwables.getStackTraceAsString(e));
            throw new BusinessException(e.getErrMsg(), e.getErrCode());
            // serviceResult.setErrorCode(e.getErrCode());
            // serviceResult.setErrorMsg(e.getErrMsg());
            // return serviceResult;
        }
        if (!response.isSuccess()) {
            // serviceResult.setErrorCode(response.getErrcode().toString());
            // serviceResult.setErrorMsg(response.getErrmsg());
            // return serviceResult;
            throw new BusinessException(response.getErrmsg(), response.getErrcode().toString());

        }
        return serviceResult.setData(response.getUserid());
    }

    /**
     * 访问 /user/get 获取用户名称
     * 
     * <pre>
     *     供测试使用！
     * </pre>
     *
     * @param accessToken access_token
     * @param userId 用户userId
     * @return 用户名称或错误信息
     */
    public ResponseResult<UserDTO> getUser(String accessToken, String userId) {
        ResponseResult<UserDTO> serviceResult = new ResponseResult<>();
        DingTalkClient client = new DefaultDingTalkClient(UrlConstant.URL_USER_GET);
        OapiUserGetRequest request = new OapiUserGetRequest();
        request.setUserid(userId);
        request.setHttpMethod("GET");

        OapiUserGetResponse response;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "getUser failed, case: {}",
                Throwables.getStackTraceAsString(e));
            serviceResult.setErrorCode(e.getErrCode());
            serviceResult.setErrorMsg(e.getErrMsg());
            return serviceResult;
        }

        UserDTO user = new UserDTO();
        user.setName(response.getName());
        user.setDingtalkUserId(response.getUserid());
        user.setAvatar(response.getAvatar());

        return serviceResult.setData(user);
    }

    /**
     * JSAPI 鉴权签名信息
     * 
     * <pre>
     *     供测试使用！
     * </pre>
     * 
     * @param url 请求 url
     * @return JSAPI 鉴权签名信息或错误信息
     */
    @PostMapping("/config")
    @ApiIgnore
    // @ApiOperation(value = "JSAPI 鉴权签名信息", notes = "JSAPI 鉴权签名信息")
    public ServiceResult<ConfigDTO> config(@RequestParam String url) {
        ServiceResult<ConfigDTO> serviceResult = new ServiceResult<>();
        ConfigDTO config = new ConfigDTO();
        String jsTicket = apiHelper.getJsTicket();

        config.setAgentId(appConfig.getAgentId());
        config.setCorpId(appConfig.getCorpId());
        config.setJsticket(jsTicket);
        config.setNonceStr(JsApiSignature.genNonce());
        config.setTimeStamp(System.currentTimeMillis() / 1000);
        String sign;
        try {
            sign = JsApiSignature.sign(url, config.getNonceStr(), config.getTimeStamp(), config.getJsticket());
        } catch (DingtalkEncryptException e) {
            serviceResult.setErrorCode(e.getCode().toString());
            serviceResult.setErrorMsg(e.getMessage());
            return serviceResult;
        }
        config.setSignature(sign);
        return serviceResult.setResult(config);
    }

}
